package com.example.demo.util;

import com.example.demo.exception.BizException;
import com.example.demo.exception.ErrorConstants;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.AntPathMatcher;
import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * ProfileUtil
 *
 * @author haochen78
 * @date 2025/7/11 13:58
 **/
public class ProfileUtil {

    // 修改配置存储结构，按文件名分别存储配置
    private static final Map<String, Map<String, Object>> CONFIG_MAP = new ConcurrentHashMap<>();
    private static final String DEFAULT_CONFIG_FILE = "application.yml";
    private static final String SECURITY_CONFIG_FILE = "security-filter.yml";
    private static final Map<String, Function<InputStream, Map<String, Object>>> PARSERS = new HashMap<>();

    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    static {
        // 注册配置文件解析器
        registerParser(DEFAULT_CONFIG_FILE);
        registerParser(SECURITY_CONFIG_FILE);
        // 加载默认配置
        loadConfig(DEFAULT_CONFIG_FILE);
        loadConfig(SECURITY_CONFIG_FILE);
    }

    public static void main(String[] args) {
        Object listClass = getYaml(SECURITY_CONFIG_FILE, "filterDecodeList1.dev.cc");
        System.out.println(listClass);
        Object listClass1 = getYaml(SECURITY_CONFIG_FILE, "filterDecodeList");
        System.out.println(listClass1);
        System.out.println(isDev());
    }

    public static boolean isDev() {
        List<Object> properties = getProperties(DEFAULT_CONFIG_FILE, "spring.profiles.active");
        if (CollectionUtils.isEmpty(properties)) {
            return false;
        }
        return StringUtils.equalsIgnoreCase((String) properties.get(0), "dev");
    }

    /**
     * 判断路径是否在Sign排除列表中
     */
    public static boolean isSignExcluded(String requestPath) {
        List<Object> properties = getProperties(SECURITY_CONFIG_FILE, "filterSignList");
        if (CollectionUtils.isEmpty(properties)) {
            return false;
        }
        return properties.stream().anyMatch(pattern -> PATH_MATCHER.match((String) pattern, requestPath));
    }

    /**
     * 获取Sign排除列表
     */
    public static List<String> getTokenExcluded() {
        List<Object> properties = getProperties(SECURITY_CONFIG_FILE, "filterTokenList");
        if (CollectionUtils.isEmpty(properties)) {
            return Collections.emptyList();
        }
        return properties.stream().map(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 判断路径是否在加解密排除列表中
     */
    public static boolean isDecodeExcluded(String requestPath) {
        List<Object> properties = getProperties(SECURITY_CONFIG_FILE, "filterDecodeList");
        if (CollectionUtils.isEmpty(properties)) {
            return false;
        }
        return properties.stream().anyMatch(pattern -> PATH_MATCHER.match((String) pattern, requestPath));
    }

    /**
     * 判断路径是否在Token排除列表中
     */
    public static boolean isTokenExcluded(String requestPath) {
        List<Object> properties = getProperties(SECURITY_CONFIG_FILE, "filterTokenList");
        if (CollectionUtils.isEmpty(properties)) {
            return false;
        }
        return properties.stream().anyMatch(pattern -> PATH_MATCHER.match((String) pattern, requestPath));
    }

    /**
     * 注册配置文件解析器
     *
     * @param fileName 文件扩展名
     */
    public static void registerParser(String fileName) {
        String extension = getFileExtension(fileName);
        if ("properties".equals(extension)) {
            PARSERS.put(fileName, ProfileUtil::parseProperties);
        }
        if ("yaml".equals(extension) || "yml".equals(extension)) {
            PARSERS.put(fileName, ProfileUtil::parseYaml);
        }
    }

    /**
     * 加载配置文件，会覆盖同名配置
     *
     * @param fileName 配置文件路径
     */
    public static void loadConfig(String fileName) {
        try (InputStream in = ProfileUtil.class.getClassLoader().getResourceAsStream(fileName)) {
            if (in != null) {
                Function<InputStream, Map<String, Object>> parser = PARSERS.getOrDefault(fileName,
                        ProfileUtil::parseProperties);
                // 存储时使用实际文件名作为键
                CONFIG_MAP.put(fileName, parser.apply(in));
            }
        } catch (IOException e) {
            System.err.println("Failed to load custom config: " + e.getMessage());
            throw new BizException(ErrorConstants.SERVER_INTERNAL_ERROR, e);
        }
    }

    /**
     * 根据指定的配置文件获取配置值
     *
     * @param fileName 配置文件名
     * @param key      配置键
     * @return 配置值
     */
    public static List<Object> getProperties(String fileName, String key) {
        Map<String, Object> fileConfig = CONFIG_MAP.get(fileName);
        if (fileConfig == null) {
            return null;
        }
        Object current = fileConfig.get(key);
        // 将结果转换为List集合
        if (current instanceof List) {
            // 若已是集合，直接转换
            return new ArrayList<>((List<?>) current);
        } else {
            // 若为单个值，包装为单元素集合
            return Collections.singletonList(current.toString());
        }
    }

    /**
     * 根据单个字符串键（.分割）获取嵌套配置中的集合
     *
     * @param fileName 配置文件名（对应CONFIG_MAP的key）
     * @param key      单个字符串键（如"nested.list"）
     * @return 最终结果集合，若路径无效返回空集合
     */
    public static List<Object> getYaml(String fileName, String key) {
        // 获取文件对应的配置根节点
        Object current = CONFIG_MAP.get(fileName);
        if (current == null) {
            return Collections.emptyList();
        }
        // 进入下一层级
        current = ((Map<?, ?>) current).get(key);
        if (current == null) {
            return Collections.emptyList();
        }
        // 将结果转换为List集合
        if (current instanceof List) {
            // 若已是集合，直接转换
            return new ArrayList<>((List<?>) current);
        } else {
            // 若为单个值，包装为单元素集合
            return Collections.singletonList(current.toString());
        }
    }

    /**
     * 解析Properties格式配置文件
     *
     * @param inputStream 输入流
     * @return 配置映射
     */
    private static Map<String, Object> parseProperties(InputStream inputStream) {
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            throw new RuntimeException("Failed to parse properties file", e);
        }
        return properties.entrySet().stream()
                .collect(Collectors.toMap(k -> k.getKey().toString(), Map.Entry::getValue));
    }

    /**
     * 解析YAML格式配置文件
     *
     * @param inputStream 输入流
     * @return 配置映射
     */
    private static Map<String, Object> parseYaml(InputStream inputStream) {
        Yaml yaml = new Yaml();
        try {
            Map<String, Object> result = new HashMap<>();
            Map<String, Object> yamlMap = yaml.load(inputStream);
            if (yamlMap != null) {
                flattenMap(yamlMap, result, "");
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse YAML file", e);
        }
    }

    /**
     * 递归展开嵌套的Map
     *
     * @param source 源Map
     * @param target 目标Map
     * @param prefix 键前缀
     */
    @SuppressWarnings("unchecked")
    private static void flattenMap(Map<String, Object> source, Map<String, Object> target, String prefix) {
        source.forEach((key, value) -> {
            String newKey = prefix.isEmpty() ? key : prefix + "." + key;
            if (value instanceof Map) {
                flattenMap((Map<String, Object>) value, target, newKey);
            } else {
                target.put(newKey, value);
            }
        });
    }

    /**
     * 获取文件扩展名
     *
     * @param fileName 文件名
     * @return 文件扩展名
     */
    private static String getFileExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }

        int lastIndex = fileName.lastIndexOf('.');
        return lastIndex >= 0 ? fileName.substring(lastIndex + 1).toLowerCase() : "";
    }

    // 私有构造函数，防止实例化
    private ProfileUtil() {
    }
}
